/*//////////////////////////////////////////////////////////////////////////////
//
//                  INTEL CORPORATION PROPRIETARY INFORMATION
//     This software is supplied under the terms of a license agreement or
//     nondisclosure agreement with Intel Corporation and may not be copied
//     or disclosed except in accordance with the terms of that agreement.
//          Copyright(c) 2002-2008 Intel Corporation. All Rights Reserved.
//
*/

#include "umc_defs.h"

#if defined (UMC_ENABLE_AAC_INT_AUDIO_DECODER)

#include "umc_aac_decoder_int.h"
#include "mp4cmn_config.h"
#include "aaccmn_adif.h"
#include "aaccmn_adts.h"
#include "aac_dec_own_int.h"
#include "aac_dec_int.h"
#include "umc_aac_decoder_params.h"
#include "vm_debug.h"

namespace UMC {

/********************************************************************/

  AudioCodec *newAACDecoderInt() { return (new AACDecoderInt); }
  AudioCodec *CreateAACDecoderInt() { return (new AACDecoderInt); }

  AACDecoderInt::AACDecoderInt()
  {
    state = NULL;
    stateMemId = 0;
  }

/********************************************************************/

  Status AACDecoderInt::Init(BaseCodecParams * init)
  {
    AACStatus result;
    AudioCodecParams *pAudioCodecInit = DynamicCast < AACDecoderParams > (init);
    Ipp32s mStateSize;

    // checks or create memory allocator;
    if (BaseCodec::Init(init) != UMC_OK) {
      vm_debug_trace(VM_DEBUG_ERROR, VM_STRING("Failed to create allocator!\n"));
      return UMC_ERR_ALLOC;
    }

    result = aacidecGetSize(&mStateSize);
    if (result != AAC_OK)
      return StatusAAC_2_UMC(result);

    if (m_pMemoryAllocator->Alloc(&stateMemId, mStateSize,
      UMC_ALLOC_PERSISTENT) != UMC_OK) {
      vm_debug_trace(VM_DEBUG_ERROR, VM_STRING("External allocation failed\n"));
      return UMC_ERR_ALLOC;
    }

    state = (AACDec *)m_pMemoryAllocator->Lock(stateMemId);
    if(!state) {
      vm_debug_trace(VM_DEBUG_ERROR, VM_STRING("External Lock failed\n"));
      return UMC_ERR_ALLOC;
    }

    result = aacidecInit(state);

    if (result != AAC_OK)
      return StatusAAC_2_UMC(result);

    initSubtype = 0;
    m_info.m_audio_object_type = AOT_UNDEF;
    m_info.m_decode_mode = DM_UNDEF_STREAM;
    m_info.m_init_stream_type = UNDEF_AUDIO;
    m_info.m_init_config_data_size = 0;
    m_info.m_sampling_frequency_index = 0;
    m_info.m_frame_number = 0;

    m_pts_prev = 0;
    params.is_valid = 0;

    if (!pAudioCodecInit)
      return UMC_OK;

    /* ***************************** *
    * usr settings for HEAAC
    * status = SetParams(init) - incorrect here
    * because default settings apply by constructor()
    * ***************************** */
    SetParams(init) ;

    if (stateMemId) {
      if (UMC_OK != m_pMemoryAllocator->Unlock(stateMemId)) {
        vm_debug_trace(VM_DEBUG_ERROR, VM_STRING("External Unlock failed\n"));
        return UMC_ERR_ALLOC;
      }
    }

    m_info.m_init_stream_type = pAudioCodecInit->m_info_in.stream_type;
    if (NULL != pAudioCodecInit->m_pData) {
      m_info.m_init_config_data_size = pAudioCodecInit->m_pData->GetDataSize();

      if (AAC_MPEG4_STREAM == m_info.m_init_stream_type) {
        Ipp8u                  *inPointer;
        sAudio_specific_config audio_config_data;
        sBitsreamBuffer        BS;
        Status                 status;

        status = MemLock();
        if (status != UMC_OK) {
          vm_debug_trace(VM_DEBUG_ERROR, VM_STRING("MemLock failed\n"));
          return status;
        }

        inPointer = (Ipp8u *)pAudioCodecInit->m_pData->GetDataPointer();
        if (NULL == inPointer) {
          return UMC_ERR_NULL_PTR;
        }

        GET_INIT_BITSTREAM(&BS, inPointer)

        BS.nDataLen = m_info.m_init_config_data_size;
        if (dec_audio_specific_config(&audio_config_data, &BS) < 0) {
          vm_debug_trace(VM_DEBUG_ERROR, VM_STRING("dec_audio_specific_config failed\n"));
          MemUnlock();
          return UMC_ERR_INIT;
        }
        /* **************************************************** *
        * if MP4 contains explicit HEAAC signalization
        * then usrParam <ModeDwnsmplHEAACprofile> is ignored
        * **************************************************** */
        if( 5 == audio_config_data.extensionAudioObjectType ){ //AOT_SBR = 5
          if( audio_config_data.extensionSamplingFrequencyIndex == audio_config_data.samplingFrequencyIndex ){
            aacidecSetSBRModeDwnmx(HEAAC_DWNSMPL_ON, state);
          } else {
            aacidecSetSBRModeDwnmx(HEAAC_DWNSMPL_OFF, state);
          }
        }
        /* END SET_PARAM OF HEAAC FROM MP4 HEADER */

        m_info.m_sampling_frequency_index =
          get_sampling_frequency_index(&audio_config_data);

        if (audio_config_data.channelConfiguration == 0) {
          aacidecSetPCE(&audio_config_data.GASpecificConfig.pce, state);
        }

        m_info.m_decode_mode = DM_RAW_STREAM;

        m_info.m_audio_object_type =
          (AudioObjectType) audio_config_data.audioObjectType;

        aacidecSetAudioObjectType(m_info.m_audio_object_type, state);

        /* Init tables */
        aacidecSetSamplingFrequency(m_info.m_sampling_frequency_index, state);
        pAudioCodecInit->m_pData->MoveDataPointer((Ipp32s)m_info.m_init_config_data_size);

        MemUnlock();
      }
    } else {
      if (AAC_MPEG4_STREAM == m_info.m_init_stream_type) {
        return UMC_ERR_INVALID_PARAMS;
      }
    }

    return UMC_OK;
  }

/********************************************************************/

  Status  AACDecoderInt::SetParams(BaseCodecParams * params) {
    AACDecoderParams *info = DynamicCast < AACDecoderParams > (params);

    if (info) {
      if ((info->ModeDecodeHEAACprofile == HEAAC_HQ_MODE ||
           info->ModeDecodeHEAACprofile == HEAAC_LP_MODE) &&
          (info->ModeDwnsmplHEAACprofile == HEAAC_DWNSMPL_ON ||
           info->ModeDwnsmplHEAACprofile == HEAAC_DWNSMPL_OFF)) {
        Status status;

        status = MemLock();
        if (status != UMC_OK) {
          vm_debug_trace(VM_DEBUG_ERROR, VM_STRING("MemLock failed\n"));
          return status;
        }

        if (state == NULL)
          return UMC_ERR_NOT_INITIALIZED;

        aacidecSetSBRModeDecode(info->ModeDecodeHEAACprofile, state);
        aacidecSetSBRModeDwnmx(info->ModeDwnsmplHEAACprofile, state);
        aacidecSetSBRSupport(info->flag_SBR_support_lev, state);

        MemUnlock();

      }
    } else {
      return UMC_ERR_NULL_PTR;
    }
    return UMC_OK;
  }

/********************************************************************/

  Status  AACDecoderInt::GetFrame(MediaData * in,
                                  MediaData * out)
  {
    AACStatus result;
    sBitsreamBuffer BS;
    Ipp32s  res;
    Ipp32s  nDecodedBytes, tmp_decodedBytes;
    sAdif_header           m_adif_header;
    sAdts_fixed_header     m_adts_fixed_header;
    sAdts_variable_header  m_adts_variable_header;
    Ipp8u  *inPointer;
    Ipp32s  inDataSize;
    Ipp64f  pts_start;
    Ipp64f  pts_end;
    Ipp32s  SbrFlagPresent, frameSize, freq, ch, decodedBytes;
    Ipp32s CRC = 0;
    Ipp32s crc_enable = 0;
    Status status;

    if (!in || !out)
      return UMC_ERR_NULL_PTR;

    status = MemLock();
    if (status != UMC_OK) {
      vm_debug_trace(VM_DEBUG_ERROR, VM_STRING("MemLock failed\n"));
      return status;
    }

    if (state == NULL)
      return UMC_ERR_NOT_INITIALIZED;

    pts_start = in->GetTime();

    aacidecInitCRC(1, state);

    if (AAC_MPEG4_STREAM != m_info.m_init_stream_type) {
      inPointer = (Ipp8u *)in->GetDataPointer();
      inDataSize = in->GetDataSize();

      if (inDataSize == 0) {
        MemUnlock();
        return UMC_ERR_NOT_ENOUGH_DATA;
      }

      result = aacidec_GetID3Len(inPointer, inDataSize, state);

      if (result != AAC_OK) {
        MemUnlock();
        return StatusAAC_2_UMC(result);
      }

      result = aacidec_SkipID3(inDataSize, &decodedBytes, state);
      in->MoveDataPointer(decodedBytes);

      if (result != AAC_OK) {
        MemUnlock();
        return StatusAAC_2_UMC(result);
      }
    }

    inPointer = (Ipp8u *)in->GetDataPointer();
    GET_INIT_BITSTREAM(&BS, inPointer)

    if (DM_UNDEF_STREAM == m_info.m_decode_mode) {
      m_info.m_audio_object_type = AOT_UNDEF;

      bs_save(&BS);
      res = dec_adif_header(&m_adif_header, &BS);
      if (res == 0) {
        sProgram_config_element *m_p_pce = &m_adif_header.pce[0];

        aacidecSetPCE(m_p_pce, state);
        m_info.m_sampling_frequency_index = m_p_pce->sampling_frequency_index;
        m_info.m_decode_mode = DM_RAW_STREAM;

        /* Init tables */
        aacidecSetSamplingFrequency(m_info.m_sampling_frequency_index, state);

        switch (m_p_pce->object_type) {
        case 0:
          m_info.m_audio_object_type = AOT_AAC_MAIN;
          break;
        case 1:
          m_info.m_audio_object_type = AOT_AAC_LC;
          break;
        case 2:
          m_info.m_audio_object_type = AOT_AAC_SSR;
          break;
        case 3:
          m_info.m_audio_object_type = AOT_AAC_LTP;
          break;
        }
        aacidecSetAudioObjectType(m_info.m_audio_object_type, state);
      } else {

        bs_restore(&BS);

        if ((0 == dec_adts_fixed_header(&m_adts_fixed_header, &BS)) &&
            (0 == dec_adts_variable_header(&m_adts_variable_header, &BS))) {

          bs_restore(&BS);
          m_info.m_sampling_frequency_index =
            m_adts_fixed_header.sampling_frequency_index;

          m_info.m_audio_object_type = (AudioObjectType)
            get_audio_object_type_by_adts_header(&m_adts_fixed_header);

          m_info.m_decode_mode = DM_ADTS_STREAM;

          aacidecSetAudioObjectType(m_info.m_audio_object_type, state);

          /* Init tables */
          aacidecSetSamplingFrequency(m_info.m_sampling_frequency_index, state);

          adts_sw = (0xFFF << 12) + ((m_adts_fixed_header.ID & 1) << 11) +
                                    ((m_adts_fixed_header.Layer & 3) << 8) +
                                    ((m_adts_fixed_header.Profile & 3) << 6) +
                                    ((m_adts_fixed_header.sampling_frequency_index & 15) << 2);
        }
      }

      m_info.m_stream_subtype = UNDEF_AUDIO_SUBTYPE;

      if (m_info.m_audio_object_type == AOT_AAC_MAIN) {
        m_info.m_stream_subtype = AAC_MAIN_PROFILE;
      } else if (m_info.m_audio_object_type == AOT_AAC_LC) {
        m_info.m_stream_subtype = AAC_LC_PROFILE;
      } else if (m_info.m_audio_object_type == AOT_AAC_SSR) {
        m_info.m_stream_subtype = AAC_SSR_PROFILE;
      } else if (m_info.m_audio_object_type == AOT_AAC_LTP) {
        m_info.m_stream_subtype = AAC_LTP_PROFILE;
      }
    }

    if (DM_UNDEF_STREAM == m_info.m_decode_mode) {
      MemUnlock();
      return UMC_ERR_UNSUPPORTED;
    }

    if (AOT_UNDEF == m_info.m_audio_object_type) {
      MemUnlock();
      return UMC_ERR_UNSUPPORTED;
    }

    if (DM_ADTS_STREAM == m_info.m_decode_mode) {
      Ipp32s DataSize = in->GetDataSize();
      Ipp8u *tmp_ptr = (Ipp8u *)in->GetDataPointer();
      Ipp32u val;
      Ipp32u *crc_ptr;
      Ipp32s crc_offset;
      Ipp32s decodedBits0, decodedBits2;
      Ipp32s num_channel;

      if (DataSize < 9) {
        MemUnlock();
        return UMC_ERR_NOT_ENOUGH_DATA;
      }

      val = (tmp_ptr[0] << 16) + (tmp_ptr[1] << 8) + tmp_ptr[2];
      DataSize -= 3;
      tmp_ptr += 3;

      while (((val & 0xFFFEFC) != adts_sw) && (DataSize > 0)) {
        val = (val << 8) + tmp_ptr[0];
        DataSize--;
        tmp_ptr++;
      }

      if ((val & 0xFFFEFC) != adts_sw) {
        in->MoveDataPointer(in->GetDataSize()-2);
        MemUnlock();
        return UMC_ERR_NOT_ENOUGH_DATA;
      }

      DataSize += 3;
      in->MoveDataPointer(in->GetDataSize()-DataSize);

      if (DataSize < 9) {
        MemUnlock();
        return UMC_ERR_NOT_ENOUGH_DATA;
      }

      inPointer = (Ipp8u *)in->GetDataPointer();
      GET_INIT_BITSTREAM(&BS, inPointer)

      crc_ptr = BS.pCurrent_dword;
      crc_offset = BS.nBit_offset;
      GET_BITS_COUNT(&BS, decodedBits0)

      dec_adts_fixed_header(&m_adts_fixed_header, &BS);
      dec_adts_variable_header(&m_adts_variable_header, &BS);

      GET_BITS_COUNT(&BS, decodedBits2)

      if (m_adts_fixed_header.protection_absent == 0) {
        Ipp32s tmp_crc;
        CRC = (Ipp32s)Getbits(&BS, 16);
        aacidecInitCRC(1, state);
        aacidecGetCRC(&tmp_crc, state);
        bs_CRC_update(crc_ptr, crc_offset, decodedBits2 - decodedBits0, (Ipp32u*)&tmp_crc);
        aacidecSetCRC(tmp_crc, state);
        crc_enable = 1;
      }

      if (aacidecSetAdtsChannelConfiguration(
          m_adts_fixed_header.channel_configuration, state) != AAC_OK ) {
        in->MoveDataPointer(3);
        MemUnlock();
        return UMC_ERR_INVALID_STREAM;
      }

      Byte_alignment(&BS);
      GET_BITS_COUNT(&BS, tmp_decodedBytes)

      num_channel = m_adts_fixed_header.channel_configuration;
      if (num_channel == 7) num_channel = 8;

      if (m_adts_variable_header.aac_frame_length >
          num_channel * 768 + tmp_decodedBytes) {
        in->MoveDataPointer(3);
        MemUnlock();
        return UMC_ERR_INVALID_STREAM;
      }

      if (m_adts_variable_header.aac_frame_length > DataSize) {
        MemUnlock();
        return UMC_ERR_NOT_ENOUGH_DATA;
      }
    }

    Byte_alignment(&BS);
    GET_BITS_COUNT(&BS, tmp_decodedBytes)
    tmp_decodedBytes >>= 3;
    nDecodedBytes = 0;

    result = aacidecGetFrame(inPointer + tmp_decodedBytes, &nDecodedBytes,
                            (Ipp16s *)out->GetDataPointer(),
                            ((Ipp32s)in->GetDataSize() - tmp_decodedBytes),
                            (Ipp32s)out->GetBufferSize() -
                            (Ipp32s)((Ipp8u *)out->GetDataPointer() - (Ipp8u *)out->GetBufferPointer()),
                            state);

    if (crc_enable) {
      if (AAC_OK == result) {
        Ipp32s streamCRC;
        aacidecGetCRC(&streamCRC, state);
        if (streamCRC != CRC) {
          printf("%i, %i\n", streamCRC, CRC);
          result = AAC_BAD_STREAM;
        }
      }
    }

    if (AAC_NOT_ENOUGH_BUFFER == result) {
      MemUnlock();
      return UMC_ERR_NOT_ENOUGH_BUFFER;
    }

    nDecodedBytes += tmp_decodedBytes;

    aacidecGetSbrFlagPresent(&SbrFlagPresent, state);
    aacidecGetFrameSize(&frameSize, state);
    aacidecGetSampleFrequency(&freq, state);
    aacidecGetChannels(&ch, state);

    if (AAC_BAD_STREAM == result) {
      Ipp32s size = frameSize * sizeof(Ipp16s) * ch;

      if (size > ((Ipp32s)out->GetBufferSize() - (Ipp32s)((Ipp8u *)out->GetDataPointer() -
        (Ipp8u *)out->GetBufferPointer()))) {
        MemUnlock();
        return UMC_ERR_NOT_ENOUGH_BUFFER;
      }
    }

    if ((0 == initSubtype) && (1 == SbrFlagPresent)) {
      initSubtype = 1;
      if (m_info.m_stream_subtype == AAC_MAIN_PROFILE) {
        m_info.m_stream_subtype =
          (UMC::AudioStreamSubType) (AAC_MAIN_PROFILE | AAC_HE_PROFILE);
      } else if (m_info.m_stream_subtype == AAC_LC_PROFILE) {
        m_info.m_stream_subtype =
          (UMC::AudioStreamSubType) (AAC_LC_PROFILE | AAC_HE_PROFILE);
      } else if (m_info.m_stream_subtype == AAC_SSR_PROFILE) {
        m_info.m_stream_subtype =
          (UMC::AudioStreamSubType) (AAC_SSR_PROFILE | AAC_HE_PROFILE);
      } else if (m_info.m_stream_subtype == AAC_LTP_PROFILE) {
        m_info.m_stream_subtype =
          (UMC::AudioStreamSubType) (AAC_LTP_PROFILE | AAC_HE_PROFILE);
      }
    }

    if (AAC_MPEG4_STREAM == m_info.m_init_stream_type) {
      in->MoveDataPointer(in->GetDataSize());
    } else {
      in->MoveDataPointer(nDecodedBytes);
    }

    if (AAC_BAD_STREAM == result) {
      Ipp32s size = frameSize * sizeof(Ipp16s) * ch;

      memset(out->GetDataPointer(),0,size);
    }

    {
      AudioData* pAudio = DynamicCast<AudioData,MediaData>(out);

      out->SetDataSize(frameSize * sizeof(Ipp16s) * ch);

      if (pts_start < 0)
        pts_start = m_pts_prev;

      m_pts_prev = pts_end = pts_start +
        ((Ipp64f)frameSize / (Ipp64f)freq);

      in->SetTime(pts_end);
      out->SetTime(pts_start, pts_end);

      m_info.m_frame_number++;

      if (pAudio) {
        pAudio->m_info.bitPerSample = 16;
        pAudio->m_info.bitrate = 0;

        pAudio->m_info.channels = ch;
        pAudio->m_info.sample_frequency = freq;
        pAudio->m_info.stream_type = PCM_AUDIO;

        switch (pAudio->m_info.channels) {
        case 1:
          pAudio->m_info.channel_mask = CHANNEL_FRONT_CENTER;
          break;
        case 2:
          pAudio->m_info.channel_mask  = CHANNEL_FRONT_LEFT;
          pAudio->m_info.channel_mask |= CHANNEL_FRONT_RIGHT;
          break;
        case 3:
          pAudio->m_info.channel_mask  = CHANNEL_FRONT_CENTER;
          pAudio->m_info.channel_mask |= CHANNEL_FRONT_LEFT;
          pAudio->m_info.channel_mask |= CHANNEL_FRONT_RIGHT;
          break;
        case 4:
          pAudio->m_info.channel_mask  = CHANNEL_FRONT_CENTER;
          pAudio->m_info.channel_mask |= CHANNEL_FRONT_LEFT;
          pAudio->m_info.channel_mask |= CHANNEL_FRONT_RIGHT;
          pAudio->m_info.channel_mask |= CHANNEL_LOW_FREQUENCY;
          break;
        case 5:
          pAudio->m_info.channel_mask  = CHANNEL_FRONT_CENTER;
          pAudio->m_info.channel_mask |= CHANNEL_FRONT_LEFT;
          pAudio->m_info.channel_mask |= CHANNEL_FRONT_RIGHT;
          pAudio->m_info.channel_mask |= CHANNEL_BACK_LEFT;
          pAudio->m_info.channel_mask |= CHANNEL_BACK_RIGHT;
          break;
        case 6:
          pAudio->m_info.channel_mask  = CHANNEL_FRONT_CENTER;
          pAudio->m_info.channel_mask |= CHANNEL_FRONT_LEFT;
          pAudio->m_info.channel_mask |= CHANNEL_FRONT_RIGHT;
          pAudio->m_info.channel_mask |= CHANNEL_BACK_LEFT;
          pAudio->m_info.channel_mask |= CHANNEL_BACK_RIGHT;
          pAudio->m_info.channel_mask |= CHANNEL_LOW_FREQUENCY;
          break;
        default:
          break;
        }
      }
    }

    MemUnlock();
    return StatusAAC_2_UMC(result);
  }

/********************************************************************/

  AACDecoderInt::~AACDecoderInt()
  {
    Close();
  }

/********************************************************************/

  Status AACDecoderInt::Close()
  {
    if (state == NULL)
      return UMC_OK;

    if (m_pMemoryAllocator == NULL) {
      return UMC_OK;
    }

    if (state) {
      m_pMemoryAllocator->Free(stateMemId);
      state = NULL;
    }

    BaseCodec::Close();

    return UMC_OK;
  }

/********************************************************************/

  Status  AACDecoderInt::Reset()
  {
    Status status;

    status = MemLock();
    if (status != UMC_OK) {
      vm_debug_trace(VM_DEBUG_ERROR, VM_STRING("MemLock failed\n"));
      return status;
    }

    if (state == NULL)
      return UMC_ERR_NOT_INITIALIZED;

    aacidecReset(state);
    MemUnlock();
    return UMC_OK;
  }

/********************************************************************/

  Status  AACDecoderInt::GetInfo(BaseCodecParams * info)
  {
    Ipp32s SbrFlagPresent;
    Status status;

    if (!info)
      return UMC_ERR_NULL_PTR;

    AudioCodecParams *p_info =
      DynamicCast < AudioCodecParams, BaseCodecParams > (info);

    status = MemLock();
    if (status != UMC_OK) {
      vm_debug_trace(VM_DEBUG_ERROR, VM_STRING("MemLock failed\n"));
      return status;
    }

    aacidecGetInfo(&params, state);

    info->m_SuggestedInputSize = params.m_SuggestedInputSize;
    info->m_SuggestedOutputSize = params.m_SuggestedOutputSize;
    info->level = AAC_LEVEL_MAIN;

    if (!p_info)
      return UMC_OK;

    if (params.is_valid) {
      info->profile = m_info.m_audio_object_type;
      aacidecGetSbrFlagPresent(&SbrFlagPresent, state);

      if (SbrFlagPresent) {
        info->profile |= AAC_PROFILE_SBR;
      }

      p_info->m_info_in.bitPerSample = params.m_info_in.bitPerSample;
      p_info->m_info_out.bitPerSample = params.m_info_out.bitPerSample;

      p_info->m_info_in.channels = params.m_info_in.channels;
      p_info->m_info_out.channels = params.m_info_out.channels;

      p_info->m_info_in.stream_type = AAC_AUDIO;
      p_info->m_info_out.stream_type = PCM_AUDIO;

      p_info->m_info_in.sample_frequency = params.m_info_in.sample_frequency;
      p_info->m_info_out.sample_frequency = params.m_info_out.sample_frequency;

      p_info->m_frame_num = m_info.m_frame_number;

      p_info->m_info_in.bitrate = params.m_info_in.bitrate;
      p_info->m_info_out.bitrate = params.m_info_out.bitrate;

      p_info->m_info_in.stream_subtype = m_info.m_stream_subtype;

      switch (p_info->m_info_in.channels) {
      case 1:
        p_info->m_info_in.channel_mask  = CHANNEL_FRONT_CENTER;
        break;
      case 2:
        p_info->m_info_in.channel_mask  = CHANNEL_FRONT_LEFT;
        p_info->m_info_in.channel_mask |= CHANNEL_FRONT_RIGHT;
        break;
      case 3:
        p_info->m_info_in.channel_mask  = CHANNEL_FRONT_CENTER;
        p_info->m_info_in.channel_mask |= CHANNEL_FRONT_LEFT;
        p_info->m_info_in.channel_mask |= CHANNEL_FRONT_RIGHT;
        break;
      case 4:
        p_info->m_info_in.channel_mask  = CHANNEL_FRONT_CENTER;
        p_info->m_info_in.channel_mask |= CHANNEL_FRONT_LEFT;
        p_info->m_info_in.channel_mask |= CHANNEL_FRONT_RIGHT;
        p_info->m_info_in.channel_mask |= CHANNEL_LOW_FREQUENCY;
        break;
      case 5:
        p_info->m_info_in.channel_mask  = CHANNEL_FRONT_CENTER;
        p_info->m_info_in.channel_mask |= CHANNEL_FRONT_LEFT;
        p_info->m_info_in.channel_mask |= CHANNEL_FRONT_RIGHT;
        p_info->m_info_in.channel_mask |= CHANNEL_BACK_LEFT;
        p_info->m_info_in.channel_mask |= CHANNEL_BACK_RIGHT;
        break;
      case 6:
        p_info->m_info_in.channel_mask  = CHANNEL_FRONT_CENTER;
        p_info->m_info_in.channel_mask |= CHANNEL_FRONT_LEFT;
        p_info->m_info_in.channel_mask |= CHANNEL_FRONT_RIGHT;
        p_info->m_info_in.channel_mask |= CHANNEL_BACK_LEFT;
        p_info->m_info_in.channel_mask |= CHANNEL_BACK_RIGHT;
        p_info->m_info_in.channel_mask |= CHANNEL_LOW_FREQUENCY;
        break;
      default:
        break;
      }

      p_info->m_info_out.channel_mask = p_info->m_info_in.channel_mask;
    } else {
      MemUnlock();
      return UMC_WRN_INFO_NOT_READY;
    }

    MemUnlock();
    return UMC_OK;
  }

/********************************************************************/

  Status AACDecoderInt::GetDuration(Ipp32f *p_duration)
  {
    Status status;

    if (!p_duration)
      return UMC_ERR_NULL_PTR;

    status = MemLock();
    if (status != UMC_OK) {
      vm_debug_trace(VM_DEBUG_ERROR, VM_STRING("MemLock failed\n"));
      return status;
    }

    if (state == NULL)
      return UMC_ERR_NOT_INITIALIZED;

    aacidecGetDuration(p_duration, state);
    MemUnlock();
    return UMC_OK;
  }

/********************************************************************/

  Status AACDecoderInt::StatusAAC_2_UMC(AACStatus st)
  {
    Status res;
    if (st == AAC_OK)
      res = UMC_OK;
    else if (st == AAC_NOT_ENOUGH_DATA)
      res = UMC_ERR_NOT_ENOUGH_DATA;
    else if (st == AAC_BAD_FORMAT)
      res = UMC_ERR_INVALID_STREAM;
    else if (st == AAC_ALLOC)
      res = UMC_ERR_ALLOC;
    else if (st == AAC_BAD_STREAM)
      res = UMC_ERR_INVALID_STREAM;
    else if (st == AAC_NULL_PTR)
      res = UMC_ERR_NULL_PTR;
    else if (st == AAC_NOT_FIND_SYNCWORD)
      res = UMC_ERR_SYNC;
    else if (st == AAC_UNSUPPORTED)
      res = UMC_ERR_UNSUPPORTED;
    else if (st == AAC_BAD_PARAMETER)
      res = UMC_ERR_UNSUPPORTED;
    else
      res = UMC_ERR_UNSUPPORTED;

    return res;
  }

/****************************************************************************/

  Status AACDecoderInt::MemLock() {
    AACDec *pOldState = state;
    state = (AACDec *)m_pMemoryAllocator->Lock(stateMemId);
    if(!state) {
      vm_debug_trace(VM_DEBUG_ERROR, VM_STRING("External Lock failed\n"));
      return UMC_ERR_ALLOC;
    }
    if (state != pOldState) {
      aacidecUpdateStateMemMap(state, (Ipp8u *)state-(Ipp8u *)pOldState);
    }
    return UMC_OK;
  }

/****************************************************************************/

  Status AACDecoderInt::MemUnlock() {
    if (stateMemId) {
      if (m_pMemoryAllocator->Unlock(stateMemId) != UMC_OK) {
        vm_debug_trace(VM_DEBUG_ERROR, VM_STRING("External Unlock failed\n"));
        return UMC_ERR_ALLOC;
      }
    }
    return UMC_OK;
  }

/****************************************************************************/
};      // namespace UMC

#endif //UMC_ENABLE_AAC_INT_AUDIO_DECODER


